﻿using System;
using System.Collections.Generic;
using System.Collections;
using MonoPhysics;
using System.Drawing;
using SdlDotNet;
using SdlDotNet.Graphics;
using Tao.Sdl;

namespace Monophysics_Demo
{
    public class BoardPolygon : RigidBody
    {
        private static Random r = new Random();
        private Color c;
        private Vector hangPoint = new Vector();
        private float restitution;
        public Vector HangPoint
        {
            get { return this.hangPoint; }
            set { hangPoint = value; }
        }
        public Color C
        { get { return c; } }
        public override float Restitution
        { get { return this.restitution; } }


        public BoardPolygon(Vector pos, float masse, List<PointD> contours, float inertia, bool ignTrans, float restitution)
        {

            this.polygonalBoundaries = new MonoPhysics.Polygon(contours, this);
            bool clockWise;
            float surface = MathGeometryHelper.CalcConvexSurface(polygonalBoundaries, out clockWise);
            this.polygonalBoundaries.Aire = surface;
            if (!clockWise)
                this.polygonalBoundaries.InvertLinks();
            if (this.polygonalBoundaries.Aire < 100)
                throw new ArgumentException("Polygone torp petit!");
            this.M = surface * masse;
            this.I = MathGeometryHelper.CalcInertia(this.polygonalBoundaries, this.M);
            //this.invM = (this.m != 0) ? 1 / this.m : 0;
            //this.invi = (this.i != 0) ? 1 / this.i : 0;
            this.rotationGrad = 0;
            this.c = Color.FromArgb(r.Next(1, 255), r.Next(1, 255), r.Next(1, 255));

            this.pos = new Vector(((MonoPhysics.Polygon)this.Shape).NonZeroCentroid);

            this.pc = new PhysicContext(new MonoPhysics.Vector(), null, false, false, false, false, false, new MonoPhysics.Vector(0, 0, 0), new Force(new Vector(), new Vector()), 0.0f, 500, 500, 0);
            //this.xnor_objectGroup = 3;
            this.and_objectGroup = 1;
            PredrawSurface();
        }


        private void RotateBy(float dAngleGrad)
        {
            // La rotation est faite par rapport au centre d'inertie (aux coordonnees relatives (0,0))
            List<PointD> al = new List<PointD>();
            float rh = hangPoint.Magnitude;
            float tetah = hangPoint.DirectionDeg;
            float theX = hangPoint.X;
            float theY = hangPoint.Y;
            hangPoint.X = (float)(theX * Math.Cos(dAngleGrad) + theY * Math.Sin(dAngleGrad));
            hangPoint.Y = (float)(theY * Math.Cos(dAngleGrad) - theX * Math.Sin(dAngleGrad));//q.QVRotate(q, hangPoint);
            #region Delegue pour manipulation arbre binaire
            BinaryTree<Circle>.ForallFunc func = delegate(Circle pt)
            {
                if (pt.Orientation != this.rotationGrad + dAngleGrad)
                {
                    float dRot = pt.Orientation - (this.rotationGrad + dAngleGrad);
                    pt.Center = RotPoint(pt.Center, dRot);
                    pt.Orientation = this.rotationGrad + dAngleGrad;
                }
            };
            #endregion
            CircularLinkedListNode<PointD, RigidBody> pts = this.polygonalBoundaries.Points;
            CircularLinkedListNode<PointD, RigidBody> parc = pts;
            do
            {
                parc.value = RotPoint(parc.value, dAngleGrad);
                parc = parc.nodes[1].fils;
            }
            while (parc != pts);
            ((Polygon)this.Shape).Tree.Tree.Forall(((Polygon)this.Shape).Tree.Tree, func);
            ((Polygon)this.Shape).UpdateAABBAndSafePoint();
        }


        private PointD RotPoint(PointD pt, float Ang)
        {
            float vX = pt.X;
            float vY = pt.Y;
            pt.X = (float)(vX * Math.Cos(Ang) + vY * Math.Sin(Ang));
            pt.Y = (float)(vY * Math.Cos(Ang) - vX * Math.Sin(Ang));
            float inv = (float)(pt.Y * Math.Cos(-Ang) - pt.X * Math.Sin(-Ang));
            return pt;
        }

        public override void DestroyBecauseFusionWith(RigidBody rb)
        {
            Demo.poly.Remove(this);
        }

        public override void FusionedWith(RigidBody r)
        {
            this.rotationGrad = 0;
        }
        public void Draw()
        {
            int loop = 0;
            List<short> x = new List<short>();
            List<short> y = new List<short>();
            bool beginBezier = false;
            LinkedListBlackCallback<PointD, RigidBody> cbk = delegate(PointD pt1, PointD pt2)
            {
                Video.Screen.Draw(new SdlDotNet.Graphics.Primitives.Line((short)(pt1.X + this.Pos.X), (short)(pt1.Y + this.Pos.Y), (short)(pt2.X + this.Pos.X), (short)(pt2.Y + this.Pos.Y)), this.c, Monophysics_Demo.Demo.AA);
                return true;
            };
            this.polygonalBoundaries.Points.Parcours_Noir(cbk);

            //Video.Screen.Blit(this.sur, Point.Round(this.PosDim.Location));
        }

        /*public void DrawBezierCurve(List<Point> pts, float pas)
        {
            for (; pas > 0.0f; pas -= 0.01)
            {
                float t = pas;
                float tm12 = (t - 1) * (t - 1);
                float tm13 = tm12 * (t - 1);
                float t2 = t * t;
                float t3 = t2 * t;

                float coeff1 = tm13;
                float coeff2 = tm12 * 3 * t;
                float coeff3 = t2 * 3 * (1 - t);
                float coeff4 = t3;
                float x = coeff1 * pts[0].X + coeff2 * pts[1].X + coeff3 * pts[2].X + coeff4 * pts[3].X;
                float y = coeff1 * pts[0].Y + coeff2 * pts[1].Y + coeff3 * pts[2].Y + coeff4 * pts[3].Y;

                pas -= 0.01;
                if(pas<
                
            }
        }
        */
        public void PredrawSurface()
        { }

        private Surface sur;

        private PhysicContext pc;
        private float masse;
        private float inertia;
        private float rotationGrad;
        private float invI;
        private float invM;
        private Polygon polygonalBoundaries;

        public override PhysicContext PhysicStats
        {
            get { return this.pc; }
            set { this.pc = value; }
        }

        public override float M
        {
            get { return this.masse; }
            set
            {
                this.masse = value;
                this.invM = ((masse == 0) ? 0 : 1 / masse);
            }
        }

        public override float I
        {
            get { return this.inertia; }
            set
            {
                this.inertia = value;
                this.invI = ((inertia == 0) ? 0 : 1 / this.inertia);
            }
        }

        public override float _invI
        { get { return this.invI; } }

        public override float _invM
        { get { return this.invM; } }



        public override float RotationGrad
        {
            get { return this.rotationGrad; }
            set
            {
                if (value != this.rotationGrad)
                {
                    this.RotateBy(rotationGrad - value);
                    rotationGrad = value;
                }
            }
        }

        public override IShape Shape
        {
            get { return this.polygonalBoundaries; }
            set { this.polygonalBoundaries = (Polygon)value; }
        }

    }
}